/**
 * ReportGear(2011)
 */
package com.reportgear.report.view.grid.editor.impl;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collections;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import com.reportgear.core.swing.layout.LayoutHelper;
import com.reportgear.core.swing.pane.base.EditorPane;
import com.reportgear.report.context.ReportContext;
import com.reportgear.report.model.ReportModel;
import com.reportgear.report.model.cell.value.FormulaObject;
import com.reportgear.report.model.script.function.Function;
import com.reportgear.report.model.script.function.FunctionManager;
import com.reportgear.report.model.script.function.Function.Type;
import com.reportgear.report.model.script.var.VarInfo;
import com.reportgear.report.model.script.var.VarManager;
import com.reportgear.report.view.JWorksheet;

/**
 * 公式编辑面板
 * 
 * @version 1.0 2011-5-2
 * @author <a herf="lexloo@gmail.com">lexloo</a>
 * @since Report 1.0
 */
public class FormulaPane extends EditorPane<FormulaObject> {
	private static final long serialVersionUID = -9125002127911251495L;
	private FormulaInputPane formulaInputPane;
	private SelectInfoPane selectInfoPane;
	private DescInfoPane descInfoPane;
	private FormulaObject formula;

	public FormulaPane() {
		this.initComponents();
	}

	private void initComponents() {
		this.setLayout(new BorderLayout());

		this.formulaInputPane = new FormulaInputPane();
		this.add(this.formulaInputPane, BorderLayout.NORTH);

		this.selectInfoPane = new SelectInfoPane();
		this.add(this.selectInfoPane, BorderLayout.CENTER);

		this.descInfoPane = new DescInfoPane();
		this.add(this.descInfoPane, BorderLayout.EAST);
	}

	// 插入文本
	private void insertText(String text) {
		this.formulaInputPane.applyText(text);
	}

	// 显示描述
	private void displayDescription(String description) {
		this.descInfoPane.showDescription(description);
	}

	// 清空描述
	protected void clearDescription() {
		this.descInfoPane.showDescription("");
	}

	// 公式输入面板
	@SuppressWarnings("serial")
	private class FormulaInputPane extends JPanel {
		private JTextArea formulaTextArea;

		private FormulaInputPane() {
			this.setLayout(new BorderLayout());

			this.add(new JLabel("公式编辑"), BorderLayout.NORTH);
			this.formulaTextArea = new JTextArea(5, 0);
			this.formulaTextArea.setLineWrap(true);
			this.add(new JScrollPane(this.formulaTextArea), BorderLayout.CENTER);

			JPanel paneBtns = new JPanel();
			paneBtns.setLayout(new GridBagLayout());
			paneBtns.setBorder(BorderFactory.createTitledBorder("输入键"));

			paneBtns.add(new OperateButton("+"), LayoutHelper.newGridBagConstraints(0, 0, 1, 1));
			paneBtns.add(new OperateButton("-"), LayoutHelper.newGridBagConstraints(1, 0, 1, 1));
			paneBtns.add(new OperateButton("*"), LayoutHelper.newGridBagConstraints(2, 0, 1, 1));
			paneBtns.add(new OperateButton("/"), LayoutHelper.newGridBagConstraints(3, 0, 1, 1));
//			paneBtns.add(new OperateButton(","), LayoutHelper.newGridBagConstraints(4, 0, 1, 1));
			
			ActionListener comboBoxListener = new ActionListener() {

				@Override
				public void actionPerformed(ActionEvent evt) {
					JComboBox comboBox = (JComboBox) evt.getSource();
					FormulaPane.this.insertText(String.valueOf(comboBox.getSelectedItem()));
				}
			};

			JComboBox columnComboBox = new JComboBox(new Character[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
					'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' });
			JComboBox rowComboBox = new JComboBox(new Character[] { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' });
			columnComboBox.addActionListener(comboBoxListener);
			rowComboBox.addActionListener(comboBoxListener);

			paneBtns.add(columnComboBox, LayoutHelper.newGridBagConstraints(0, 1, 2, 1));
			paneBtns.add(rowComboBox, LayoutHelper.newGridBagConstraints(2, 1, 2, 1));
			this.add(paneBtns, BorderLayout.EAST);
		}

		private void applyText(String text) {
			if ((text == null) || (text.length() <= 0)) {
				return;
			}

			this.formulaTextArea.insert(text, this.formulaTextArea.getCaretPosition());
			this.formulaTextArea.getText();
			if (text.indexOf("()") != -1) {
				this.formulaTextArea.setCaretPosition(this.formulaTextArea.getCaretPosition() - 1);
			}

			this.formulaTextArea.requestFocus();
		}

		private String getText() {
			return this.formulaTextArea.getText().trim();
		}
	}

	// 选择信息面板
	@SuppressWarnings("serial")
	private class SelectInfoPane extends JPanel {
		private CatalogPane catalogPane;
		private ObjectSelectPane objSelectPane;

		private SelectInfoPane() {
			this.setLayout(new BorderLayout());
			this.objSelectPane = new ObjectSelectPane();

			this.catalogPane = new CatalogPane(this.objSelectPane);
			this.add(this.catalogPane, BorderLayout.WEST);

			this.add(this.objSelectPane, BorderLayout.CENTER);
		}
	}

	// 分类面板
	@SuppressWarnings("serial")
	private class CatalogPane extends JPanel {
		private FunctionPane fnPane;
		private VarAndParamPane vapPane;

		private CatalogPane(ObjectSelectPane selectPane) {
			this.setLayout(new BorderLayout());

			this.fnPane = new FunctionPane();
			this.add(this.fnPane, BorderLayout.CENTER);
			this.fnPane.setSelectPane(selectPane);

			this.vapPane = new VarAndParamPane();
			this.add(this.vapPane, BorderLayout.SOUTH);
			this.vapPane.setSelectPane(selectPane);
		}
	}

	// 函数选择面板
	@SuppressWarnings("serial")
	private class FunctionPane extends JPanel {
		private JList fnCatalog;
		private ObjectSelectPane selectPane;

		private FunctionPane() {
			this.setLayout(new BorderLayout());
			this.setPreferredSize(new Dimension(180, 32));

			this.initCatalog();

			this.add(new JLabel("函数"), BorderLayout.NORTH);
			this.add(new JScrollPane(this.fnCatalog), BorderLayout.CENTER);
		}

		// 初始化函数分类
		private void initCatalog() {
			this.fnCatalog = new JList(Function.Type.values());
			this.fnCatalog.addListSelectionListener(new ListSelectionListener() {

				@Override
				public void valueChanged(ListSelectionEvent evt) {
					if (evt.getValueIsAdjusting()) {
						return;
					}

					JList list = (JList) evt.getSource();

					Function.Type type = (Type) list.getSelectedValue();

					selectPane.updateByFunctionType(type);

					FormulaPane.this.clearDescription();
				}
			});
		}

		private void setSelectPane(ObjectSelectPane selectPane) {
			this.selectPane = selectPane;
		}
	}

	// 参数选择面板
	@SuppressWarnings("serial")
	private class VarAndParamPane extends JPanel {
		private JList varList;
		private ObjectSelectPane selectPane;

		private VarAndParamPane() {
			this.setLayout(new BorderLayout());

			this.add(new JLabel("变量与参数"), BorderLayout.NORTH);
			varList = new JList(new String[] { "变量", "报表参数" });
			varList.setBorder(BorderFactory.createLineBorder(Color.GRAY));
			this.add(varList, BorderLayout.CENTER);

			varList.addListSelectionListener(new ListSelectionListener() {

				@Override
				public void valueChanged(ListSelectionEvent evt) {
					if (evt.getValueIsAdjusting()) {
						return;
					}

					JList list = (JList) evt.getSource();

					if (list.getSelectedIndex() == 0) {
						selectPane.updateByVars();
					} else if (list.getSelectedIndex() == 1) {
						selectPane.updateByParameters();
					}

					FormulaPane.this.clearDescription();
				}
			});
		}

		private void setSelectPane(ObjectSelectPane selectPane) {
			this.selectPane = selectPane;
		}
	}

	// 对象选择面板
	@SuppressWarnings("serial")
	private class ObjectSelectPane extends JPanel {
		private JList itemsList;

		private ObjectSelectPane() {
			this.setLayout(new BorderLayout());
			this.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));

			this.itemsList = new JList();
			this.add(new JLabel("选择"), BorderLayout.NORTH);
			this.add(new JScrollPane(this.itemsList), BorderLayout.CENTER);
			this.itemsList.addMouseListener(new MouseAdapter() {

				@Override
				public void mouseClicked(MouseEvent evt) {
					if (evt.getClickCount() == 2) {
						JList list = (JList) evt.getSource();

						Object value = list.getSelectedValue();
						if (value instanceof Function) {
							FormulaPane.this.insertText(value.toString() + "()");
						} else if (value instanceof VarInfo) {
							FormulaPane.this.insertText(value.toString());
						}
					}
				}
			});

			this.itemsList.addListSelectionListener(new ListSelectionListener() {

				@Override
				public void valueChanged(ListSelectionEvent evt) {
					JList list = (JList) evt.getSource();

					Object value = list.getSelectedValue();
					if (value instanceof Function) {
						FormulaPane.this.displayDescription(((Function) value).getDescription());
					} else if (value instanceof VarInfo) {

						FormulaPane.this.displayDescription(((VarInfo) value).desc);
					}
				}
			});
		}

		/**
		 * 更新参数
		 */
		public void updateByParameters() {
			JWorksheet worksheet = ReportContext.INSTANCE.getCurrentWorkSheet();
			if (worksheet == null) {
				this.itemsList.setListData(new Object[0]);
			} else {
				ReportModel model = worksheet.getReportModel();
				this.itemsList.setListData(model.getParameters().toArray());
			}
		}

		/**
		 * 更新变量
		 */
		public void updateByVars() {
			this.itemsList.setListData(VarManager.INSTANCE.getAllVars());
		}

		/**
		 * 通过函数类型更新
		 * 
		 * @param type
		 *            函数类型
		 */
		private void updateByFunctionType(Function.Type type) {
			List<Function> fnList = FunctionManager.INSTANCE.getTypeList(type);

			Collections.sort(fnList);

			this.itemsList.setListData(fnList.toArray());
		}
	}

	// 描述信息显示面板
	@SuppressWarnings("serial")
	private static class DescInfoPane extends JPanel {
		private JTextArea descInfoArea;

		private DescInfoPane() {
			this.setLayout(new BorderLayout());
			this.setPreferredSize(new Dimension(200, 32));
			this.add(new JLabel("说明"), BorderLayout.NORTH);

			this.descInfoArea = new JTextArea();
			this.descInfoArea.setEditable(false);
			this.add(new JScrollPane(this.descInfoArea), BorderLayout.CENTER);
		}

		private void showDescription(String description) {
			this.descInfoArea.setText(description);
		}
	}

	/**
	 * 操作按钮
	 */
	@SuppressWarnings("serial")
	private class OperateButton extends JButton implements ActionListener {
		public OperateButton(String text) {
			super(text);
			addActionListener(this);
		}

		@Override
		public Dimension getPreferredSize() {
			return new Dimension(42, 32);
		}

		public void actionPerformed(ActionEvent evt) {
			FormulaPane.this.insertText(this.getText());
		}
	}

	@Override
	public void populate(FormulaObject formula) {
		this.formula = formula;
		String value = formula.getFormula();

		if (value == null) {
			return;
		} else {
			this.formulaInputPane.applyText(value);
		}
	}

	@Override
	public FormulaObject update() {
		this.formula.setFormula(this.formulaInputPane.getText());

		return this.formula;
	}

	@Override
	public int showDialog(Component owner) {
		return this.showDialog(SwingUtilities.getWindowAncestor(owner), "公式编辑", 600, 400);
	}
}
